<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<title>Freetype OpenGL: demo-distance-field.c</title>

<link href="tabs.css" rel="stylesheet" type="text/css"/>
<link href="style.css" rel="stylesheet" type="text/css" />



</head>
<body>
<div id="content"><!-- do not remove this div! -->

<div id="top"><!-- do not remove this div! -->

  
  <div id="titlearea">
    
    <div id="projectname">Freetype OpenGL</div>
    
    
    <div id="projectbrief">A high quality OpenGL text rendering engine for C</div>
    
  </div>
  

<!--

<div id="titlearea">
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  
  
  <td style="padding-left: 0.5em;">
   <div id="projectname">Freetype OpenGL
   &#160;<span id="projectnumber">0.1</span>
   </div>
   <div id="projectbrief">A high quality OpenGL text rendering engine for C</div>
  </td>
  
  
  
   
  
 </tr>
 </tbody>
</table>
</div>
-->


<!-- Generated by Doxygen 1.8.0 -->
<script type="text/javascript" src="dynsections.js"></script>
</div>
<div class="header">
  <div class="headertitle">
<div class="title">demo-distance-field.c</div>  </div>
</div><!--header-->
<div class="contents">
<div class="fragment"><pre class="fragment"><span class="comment">/* =========================================================================</span>
<span class="comment"> * Freetype GL - A C OpenGL Freetype engine</span>
<span class="comment"> * Platform:    Any</span>
<span class="comment"> * WWW:         http://code.google.com/p/freetype-gl/</span>
<span class="comment"> * -------------------------------------------------------------------------</span>
<span class="comment"> * Copyright 2011 Nicolas P. Rougier. All rights reserved.</span>
<span class="comment"> *</span>
<span class="comment"> * Redistribution and use in source and binary forms, with or without</span>
<span class="comment"> * modification, are permitted provided that the following conditions are met:</span>
<span class="comment"> *</span>
<span class="comment"> *  1. Redistributions of source code must retain the above copyright notice,</span>
<span class="comment"> *     this list of conditions and the following disclaimer.</span>
<span class="comment"> *</span>
<span class="comment"> *  2. Redistributions in binary form must reproduce the above copyright</span>
<span class="comment"> *     notice, this list of conditions and the following disclaimer in the</span>
<span class="comment"> *     documentation and/or other materials provided with the distribution.</span>
<span class="comment"> *</span>
<span class="comment"> * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER &#39;&#39;AS IS&#39;&#39; AND ANY EXPRESS OR</span>
<span class="comment"> * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF</span>
<span class="comment"> * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO</span>
<span class="comment"> * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,</span>
<span class="comment"> * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES</span>
<span class="comment"> * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;</span>
<span class="comment"> * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND</span>
<span class="comment"> * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT</span>
<span class="comment"> * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF</span>
<span class="comment"> * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</span>
<span class="comment"> *</span>
<span class="comment"> * The views and conclusions contained in the software and documentation are</span>
<span class="comment"> * those of the authors and should not be interpreted as representing official</span>
<span class="comment"> * policies, either expressed or implied, of Nicolas P. Rougier.</span>
<span class="comment"> * ========================================================================= */</span>
<span class="preprocessor">#include &quot;freetype-gl.h&quot;</span>

<span class="preprocessor">#include &quot;edtaa3func.h&quot;</span>
<span class="preprocessor">#include &quot;<a class="code" href="font-manager_8h.html">font-manager.h</a>&quot;</span>
<span class="preprocessor">#include &quot;<a class="code" href="vertex-buffer_8h.html">vertex-buffer.h</a>&quot;</span>
<span class="preprocessor">#include &quot;<a class="code" href="text-buffer_8h.html">text-buffer.h</a>&quot;</span>
<span class="preprocessor">#include &quot;<a class="code" href="markup_8h.html">markup.h</a>&quot;</span>
<span class="preprocessor">#include &quot;<a class="code" href="shader_8h.html">shader.h</a>&quot;</span>

<span class="preprocessor">#define max(a,b) ((a) &gt; (b) ? (a) : (b))</span>
<span class="preprocessor"></span><span class="preprocessor">#define min(a,b) ((a) &lt; (b) ? (a) : (b))</span>
<span class="preprocessor"></span>

<span class="comment">// ------------------------------------------------------- typedef &amp; struct ---</span>
<span class="keyword">typedef</span> <span class="keyword">struct </span>{
    <span class="keywordtype">float</span> x, y, zoom;
} viewport_t;

<span class="comment">// ------------------------------------------------------- global variables ---</span>
<a name="_a0"></a><a class="code" href="structtexture__atlas__t.html" title="A texture atlas is used to pack several small regions into a single texture.">texture_atlas_t</a> * atlas = 0;
viewport_t viewport = {0,0,1};
GLuint program = 0;


<span class="comment">// ---------------------------------------------------------------- display ---</span>
<span class="keywordtype">void</span>
display( <span class="keywordtype">void</span> )
{
    <span class="keywordtype">int</span> v[4];
    glGetIntegerv( GL_VIEWPORT, v );
    GLuint width  = v[2];
    GLuint height = v[3];
    glClearColor(0.5,0.5,0.5,1.00);
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, atlas-&gt;<a name="a1"></a><a class="code" href="structtexture__atlas__t.html#a03e72bd01b6e5e97c0cc032d22c11c45" title="Texture identity (OpenGL)">id</a>);
    glEnable( GL_TEXTURE_2D );
    glEnable( GL_BLEND );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

    GLuint handle;
    handle = glGetUniformLocation( program, <span class="stringliteral">&quot;texture&quot;</span> );
    glUniform1i( handle, 0);

    <span class="keywordtype">int</span> x = viewport.x;
    <span class="keywordtype">int</span> y = viewport.y;
    width *= viewport.zoom;
    height *= viewport.zoom;

    glColor4f( 1.0, 1.0, 1.0, 1.0 );
    glPushMatrix();
    glBegin(GL_QUADS);
    glTexCoord2f( 0, 1 ); glVertex2i( x, y );
    glTexCoord2f( 0, 0 ); glVertex2i( x, y+height );
    glTexCoord2f( 1, 0 ); glVertex2i( x+width, y+height );
    glTexCoord2f( 1, 1 ); glVertex2i( x+width, y );
    glEnd();

    glPopMatrix();
    glutSwapBuffers( );
}


<span class="comment">// ----------------------------------------------------------- mouse_motion ---</span>
<span class="keywordtype">void</span>
mouse_motion( <span class="keywordtype">int</span> x, <span class="keywordtype">int</span> y )
{
    <span class="keywordtype">int</span> v[4];
    glGetIntegerv( GL_VIEWPORT, v );
    GLfloat width = v[2], height = v[3];
    <span class="keywordtype">float</span> nx = min( max( x/width, 0.0), 1.0 );
    <span class="keywordtype">float</span> ny = 1-min( max( y/height, 0.0), 1.0 );
    viewport.x = nx*width*(1-viewport.zoom);
    viewport.y = ny*height*(1-viewport.zoom);
    glutPostRedisplay();
}


<span class="comment">// ------------------------------------------------------------- mouse_drag ---</span>
<span class="keywordtype">void</span>
mouse_drag( <span class="keywordtype">int</span> x, <span class="keywordtype">int</span> y )
{
    <span class="keyword">static</span> <span class="keywordtype">int</span> _x=-1, _y=-1;
    <span class="keywordflow">if</span>( (_x == -1) &amp;&amp; (_y == -1) )
    {
        _x = x; _y = y;
        <span class="keywordflow">return</span>;
    }
    <span class="keywordtype">int</span> dy = y - _y;
    <span class="keywordflow">if</span> (dy &lt; 0)
    {
        viewport.zoom *= 1.05;
    }
    <span class="keywordflow">else</span>
    {
        viewport.zoom /= 1.05;
    }
    _x = x; _y = y;
    mouse_motion(x,y);
}


<span class="comment">// ---------------------------------------------------------------- reshape ---</span>
<span class="keywordtype">void</span> reshape(<span class="keywordtype">int</span> width, <span class="keywordtype">int</span> height)
{
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, width, 0, height, -1, 1);
    glMatrixMode(GL_MODELVIEW);
    glutPostRedisplay();
}


<span class="comment">// --------------------------------------------------------------- keyboard ---</span>
<span class="keywordtype">void</span>
keyboard( <span class="keywordtype">unsigned</span> <span class="keywordtype">char</span> key, <span class="keywordtype">int</span> x, <span class="keywordtype">int</span> y )
{
    <span class="keywordflow">if</span> ( key == 27 )
    {
        exit( 1 );
    }
}


<span class="comment">// ------------------------------------------------------ make_distance_map ---</span>
<span class="keywordtype">unsigned</span> <span class="keywordtype">char</span> *
make_distance_map( <span class="keywordtype">unsigned</span> <span class="keywordtype">char</span> *img,
                   <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> width, <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> height )
{
    <span class="keywordtype">short</span> * xdist = (<span class="keywordtype">short</span> *)  malloc( width * height * <span class="keyword">sizeof</span>(<span class="keywordtype">short</span>) );
    <span class="keywordtype">short</span> * ydist = (<span class="keywordtype">short</span> *)  malloc( width * height * <span class="keyword">sizeof</span>(<span class="keywordtype">short</span>) );
    <span class="keywordtype">double</span> * gx   = (<span class="keywordtype">double</span> *) calloc( width * height, <span class="keyword">sizeof</span>(<span class="keywordtype">double</span>) );
    <span class="keywordtype">double</span> * gy      = (<span class="keywordtype">double</span> *) calloc( width * height, <span class="keyword">sizeof</span>(<span class="keywordtype">double</span>) );
    <span class="keywordtype">double</span> * data    = (<span class="keywordtype">double</span> *) calloc( width * height, <span class="keyword">sizeof</span>(<span class="keywordtype">double</span>) );
    <span class="keywordtype">double</span> * outside = (<span class="keywordtype">double</span> *) calloc( width * height, <span class="keyword">sizeof</span>(<span class="keywordtype">double</span>) );
    <span class="keywordtype">double</span> * inside  = (<span class="keywordtype">double</span> *) calloc( width * height, <span class="keyword">sizeof</span>(<span class="keywordtype">double</span>) );
    <span class="keywordtype">int</span> i;

    <span class="comment">// Convert img into double (data)</span>
    <span class="keywordtype">double</span> img_min = 255, img_max = -255;
    <span class="keywordflow">for</span>( i=0; i&lt;width*height; ++i)
    {
        <span class="keywordtype">double</span> v = img[i];
        data[i] = v;
        <span class="keywordflow">if</span> (v &gt; img_max) img_max = v;
        <span class="keywordflow">if</span> (v &lt; img_min) img_min = v;
    }
    <span class="comment">// Rescale image levels between 0 and 1</span>
    <span class="keywordflow">for</span>( i=0; i&lt;width*height; ++i)
    {
        data[i] = (img[i]-img_min)/img_max;
    }

    <span class="comment">// Compute outside = edtaa3(bitmap); % Transform background (0&#39;s)</span>
    computegradient( data, height, width, gx, gy);
    edtaa3(data, gx, gy, height, width, xdist, ydist, outside);
    <span class="keywordflow">for</span>( i=0; i&lt;width*height; ++i)
        <span class="keywordflow">if</span>( outside[i] &lt; 0 )
            outside[i] = 0.0;

    <span class="comment">// Compute inside = edtaa3(1-bitmap); % Transform foreground (1&#39;s)</span>
    memset(gx, 0, <span class="keyword">sizeof</span>(<span class="keywordtype">double</span>)*width*height );
    memset(gy, 0, <span class="keyword">sizeof</span>(<span class="keywordtype">double</span>)*width*height );
    <span class="keywordflow">for</span>( i=0; i&lt;width*height; ++i)
        data[i] = 1 - data[i];
    computegradient( data, height, width, gx, gy);
    edtaa3(data, gx, gy, height, width, xdist, ydist, inside);
    <span class="keywordflow">for</span>( i=0; i&lt;width*height; ++i)
        <span class="keywordflow">if</span>( inside[i] &lt; 0 )
            inside[i] = 0.0;

    <span class="comment">// distmap = outside - inside; % Bipolar distance field</span>
    <span class="keywordtype">unsigned</span> <span class="keywordtype">char</span> *out = (<span class="keywordtype">unsigned</span> <span class="keywordtype">char</span> *) malloc( width * height * <span class="keyword">sizeof</span>(<span class="keywordtype">unsigned</span> <span class="keywordtype">char</span>) );
    <span class="keywordflow">for</span>( i=0; i&lt;width*height; ++i)
    {
        outside[i] -= inside[i];
        outside[i] = 128+outside[i]*16;
        <span class="keywordflow">if</span>( outside[i] &lt; 0 ) outside[i] = 0;
        <span class="keywordflow">if</span>( outside[i] &gt; 255 ) outside[i] = 255;
        out[i] = 255 - (<span class="keywordtype">unsigned</span> char) outside[i];
        <span class="comment">//out[i] = (unsigned char) outside[i];</span>
    }

    free( xdist );
    free( ydist );
    free( gx );
    free( gy );
    free( data );
    free( outside );
    free( inside );
    <span class="keywordflow">return</span> out;
}




<span class="comment">// ------------------------------------------------------------------- main ---</span>
<span class="keywordtype">int</span>
main( <span class="keywordtype">int</span> argc, <span class="keywordtype">char</span> **argv )
{
    glutInit( &amp;argc, argv );
    glutInitWindowSize( 512, 512 );
    glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
    glutCreateWindow( <span class="stringliteral">&quot;Freetype OpenGL width shaders&quot;</span> );
    glutReshapeFunc( reshape );
    glutDisplayFunc( display );
    glutMotionFunc( mouse_drag );
    glutPassiveMotionFunc( mouse_motion );
    glutKeyboardFunc( keyboard );


    <span class="keywordtype">unsigned</span> <span class="keywordtype">char</span> *map;
    <a name="_a2"></a><a class="code" href="structtexture__font__t.html" title="Texture font structure.">texture_font_t</a> * font;
    <span class="keyword">const</span> <span class="keywordtype">char</span> *filename = <span class="stringliteral">&quot;fonts/Vera.ttf&quot;</span>;
    <span class="keyword">const</span> <span class="keywordtype">wchar_t</span> *cache = L<span class="stringliteral">&quot; !\&quot;#$%&amp;&#39;()*+,-./0123456789:;&lt;=&gt;?&quot;</span>
                           L<span class="stringliteral">&quot;@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_&quot;</span>
                           L<span class="stringliteral">&quot;`abcdefghijklmnopqrstuvwxyz{|}~&quot;</span>;

    atlas = <a name="a3"></a><a class="code" href="group__texture-atlas.html#ga7769be70f630e0a8a8b320525a07382d" title="Creates a new empty texture atlas.">texture_atlas_new</a>( 512, 512, 1 );
    font = <a name="a4"></a><a class="code" href="group__texture-font.html#ga904424e7b0e2be14b694599b5c483e64" title="This function creates a new texture font from given filename and size.">texture_font_new</a>( atlas, filename, 72 );
    <a name="a5"></a><a class="code" href="group__texture-font.html#ga912b65dd3d45ced38640cdfbecbb51c5" title="Request the loading of several glyphs at once.">texture_font_load_glyphs</a>( font, cache );
    <a name="a6"></a><a class="code" href="group__texture-font.html#gaa894ab1def90197eaad58b578e7a2440" title="Delete a texture font.">texture_font_delete</a>( font );

    fprintf( stderr, <span class="stringliteral">&quot;Generating distance map...\n&quot;</span> );
    map = make_distance_map(atlas-&gt;<a name="a7"></a><a class="code" href="structtexture__atlas__t.html#a80f633ead9dbf1fb0c49503324f30753" title="Atlas data.">data</a>, atlas-&gt;<a name="a8"></a><a class="code" href="structtexture__atlas__t.html#aa1fb802d48b70dc43e06e88f55f986aa" title="Width (in pixels) of the underlying texture.">width</a>, atlas-&gt;<a name="a9"></a><a class="code" href="structtexture__atlas__t.html#a724b0e35c619f88b231eba83c39095cb" title="Height (in pixels) of the underlying texture.">height</a>);
    fprintf( stderr, <span class="stringliteral">&quot;done !\n&quot;</span>);

    memcpy( atlas-&gt;<a class="code" href="structtexture__atlas__t.html#a80f633ead9dbf1fb0c49503324f30753" title="Atlas data.">data</a>, map, atlas-&gt;<a class="code" href="structtexture__atlas__t.html#aa1fb802d48b70dc43e06e88f55f986aa" title="Width (in pixels) of the underlying texture.">width</a>*atlas-&gt;<a class="code" href="structtexture__atlas__t.html#a724b0e35c619f88b231eba83c39095cb" title="Height (in pixels) of the underlying texture.">height</a>*<span class="keyword">sizeof</span>(<span class="keywordtype">unsigned</span> <span class="keywordtype">char</span>) );
    free(map);
    <a name="a10"></a><a class="code" href="group__texture-atlas.html#ga9200360ad560fca395e20ca80463dfd8" title="Upload atlas to video memory.">texture_atlas_upload</a>( atlas );

    <span class="comment">// Create the GLSL program</span>
    program = <a name="a11"></a><a class="code" href="group__shader.html#ga2b7a0078428da8b7fd08b17b498de7f3" title="Load a vertex and fragment shader sources and build program.">shader_load</a>( <span class="stringliteral">&quot;shaders/distance-field.vert&quot;</span>,
                           <span class="stringliteral">&quot;shaders/distance-field.frag&quot;</span> );
    glUseProgram( program );

    glutMainLoop( );
    <span class="keywordflow">return</span> 0;
}
</pre></div> </div><!-- contents -->
</div>
</body>
</html>
